package com.blog;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.Address;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.*;
import java.util.Date;
import java.util.Properties;

public class ImgMail {

	public static void main(String[] args) throws Exception {
		// 1. 创建参数配置, 用于连接邮件服务器的参数配置
		Properties props = new Properties(); // 参数配置
		props.setProperty("mail.transport.protocol", "smtp"); // 使用的协议（JavaMail规范要求）smtp或pop3
		props.setProperty("mail.smtp.host", "smtp.qq.com"); // 发件人的邮箱的 SMTP 服务器地址
		props.setProperty("mail.smtp.port", "465"); // 协议端口
		props.setProperty("mail.smtp.auth", "true"); // 需要请求认证

		// QQ:需要SSL安全认证
		props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
		props.setProperty("mail.smtp.socketFactory.fallback", "false");
		props.setProperty("mail.smtp.socketFactory.port", "465");

		// 2. 根据配置创建会话对象, 用于和邮件服务器交互
		Session session = Session.getInstance(props);
		session.setDebug(true); // 开启session的日志记录

		// 3. 创建一封邮件
		MimeMessage message = createMimeMessage(session, "1665741813@qq.com", "suoyue_zhan@163.com");

		// 4. 根据 Session 获取邮件传输对象
		Transport transport = session.getTransport();

		// 5. 使用 邮箱账号 和 密码 连接邮件服务器, 这里认证的邮箱必须与 message 中的发件人邮箱一致, 否则报错
		//
		// PS_01: 成败的判断关键在此一句, 如果连接服务器失败, 都会在控制台输出相应失败原因的 log,
		// 仔细查看失败原因, 有些邮箱服务器会返回错误码或查看错误类型的链接, 根据给出的错误
		// 类型到对应邮件服务器的帮助网站上查看具体失败原因。
		//
		// PS_02: 连接失败的原因通常为以下几点, 仔细检查代码:
		// (1) 邮箱没有开启 SMTP 服务;
		// (2) 邮箱密码错误, 例如某些邮箱开启了独立密码;
		// (3) 邮箱服务器要求必须要使用 SSL 安全连接;
		// (4) 请求过于频繁或其他原因, 被邮件服务器拒绝服务;
		// (5) 如果以上几点都确定无误, 到邮件服务器网站查找帮助。
		//
		// PS_03: 仔细看log, 认真看log, 看懂log, 错误原因都在log已说明。
		//
		// PS_04：获取QQ授权码：https://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=1001256
		transport.connect("1665741813@qq.com", "xxoo"); // 邮箱/授权码（有的直接用密码）

		// 6. 发送邮件, 发到所有的收件地址, message.getAllRecipients() 获取到的是在创建邮件对象时添加的所有收件人, 抄送人,
		// 密送人
		transport.sendMessage(message, message.getAllRecipients());

		// 7. 关闭连接
		transport.close();
	}

	// MimeMessage：图片+附件
	public static MimeMessage createMimeMessage(Session session, String sendMail, String receiveMail) throws Exception {
		// 1. 创建一封邮件
		MimeMessage message = new MimeMessage(session);
		// 邮件：标题、正文、收件人、发件人 {附件、图片、视频...}
		// 2. From: 发件人（昵称有广告嫌疑，避免被邮件服务器误认为是滥发广告以至返回失败，请修改昵称）
		Address address = new InternetAddress(sendMail, "发件人姓名setFrom", "UTF-8");
		message.setFrom(address);

		// 3. To: 收件人（可以增加多个收件人、抄送、密送）
		// CC:抄送人，BCC:密送
		message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(receiveMail, "收件人A", "UTF-8"));
//		message.setRecipient(MimeMessage.RecipientType.CC, new InternetAddress(cReceiveMail, "抄送人用户", "UTF-8"));
//		message.setRecipient(MimeMessage.RecipientType.BCC, new InternetAddress(bReceiveMail, "密送用户", "UTF-8"));

		// 4. Subject: 邮件主题（标题有广告嫌疑，避免被邮件服务器误认为是滥发广告以至返回失败，请修改标题）
		message.setSubject("这是标题(图片+附件)..setSubject", "UTF-8");


		// 创建图片“节点”
		MimeBodyPart imagePart = new MimeBodyPart();
		DataHandler imageDataHandler = new DataHandler(new FileDataSource("image//端口.png")); // 读取本地文件
		imagePart.setDataHandler(imageDataHandler); // 将图片数据添加到“节点”
		imagePart.setContentID("img1"); // 为“节点”设置一个唯一编号（在文本“节点”将引用该ID）

		// 创建文本“节点”：目的是为了加载图片
		MimeBodyPart textPart = new MimeBodyPart();
		// 这里添加图片的方式是将整个图片包含到邮件内容中, 实际上也可以以 http 链接的形式添加网络图片
		textPart.setContent("正文内容...  这是一张图片<br/><img src='cid:img1'/>", "text/html;charset=UTF-8");

		//  （文本+图片）设置 文本 和 图片 “节点”的关系（将 文本 和 图片 “节点”合成一个混合“节点”）
		MimeMultipart mm_text_image = new MimeMultipart();
		mm_text_image.addBodyPart(textPart);
		mm_text_image.addBodyPart(imagePart);
		mm_text_image.setSubType("related"); // 关联关系

		//  将 文本+图片 的混合“节点”封装成一个普通“节点”
		MimeBodyPart text_image = new MimeBodyPart();
		text_image.setContent(mm_text_image);
				
				
		// 创建附件“节点”
		MimeBodyPart attachment = new MimeBodyPart();
		DataHandler attDataHandler = new DataHandler
					(new FileDataSource("image//端口.png"));  // 读取本地文件
		attachment.setDataHandler(attDataHandler);                                             // 将附件数据添加到“节点”
		//给附件设置文件名
		attachment.setFileName(MimeUtility.encodeText(attDataHandler.getName()));              // 设置附件的文件名（需要编码）
		// 设置（文本+图片）和 附件 的关系（合成一个大的混合“节点” / Multipart ）
		MimeMultipart mm = new MimeMultipart();
		mm.addBodyPart(text_image);
		mm.addBodyPart(attachment);     // 如果有多个附件，可以创建多个多次添加
		mm.setSubType("mixed");         // 混合关系
		
		// Content: 邮件正文（可以使用html标签）（内容有广告嫌疑，避免被邮件服务器误认为是滥发广告以至返回失败，请修改发送内容）
		message.setContent(mm, "text/html;charset=utf-8");
				
		//  设置整个邮件的关系（将最终的混合“节点”作为邮件的内容添加到邮件对象）
		message.setContent(mm);
				
				
		// 设置发件时间
		message.setSentDate(new Date());

		// 保存设置
		message.saveChanges();

		return message;
	}

}
